package com.cmwa.solution.sys.attach.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;

import com.cmwa.solution.base.entity.Employee;
import com.cmwa.solution.base.entity.Page;
import com.cmwa.solution.base.entity.SearchParam;
import com.cmwa.solution.exception.ValidateFailedException;
import com.cmwa.solution.sys.attach.dao.AttachDao;
import com.cmwa.solution.sys.attach.entity.AttachRelExtVo;
import com.cmwa.solution.sys.attach.entity.AttachVo;
import com.cmwa.solution.sys.attach.entity.FileVo;
import com.cmwa.solution.sys.attach.service.AttachService;
import com.cmwa.solution.sys.permission.authority.service.AuthorityService;
import com.cmwa.solution.utils.Constant;
import com.cmwa.solution.utils.FileUtil;
import com.cmwa.solution.utils.HttpDownFileZipUtil;
import com.cmwa.solution.utils.SessionUtils;

/**
 * @author zhengqq
 * @date 2018年9月3日
 */
@Service
public class AttachServiceImpl implements AttachService {
	
	private static final Log log = LogFactory.getLog(AttachServiceImpl.class);

	@Resource
	private AttachDao attachDao;
	@Resource
	private AuthorityService authorityService;
	
	@Override
	public AttachVo findById(String attId) {
		return attachDao.findById(attId);
	}
	
	@Override
	public AttachVo findAttachAndRelByAttId(String attId) {
		return attachDao.findAttachAndRelByAttId(attId);
	}

	@Override
	public void addAttach(AttachVo vo) {
		attachDao.addAttach(vo);
	}
	
	@Override
	public void deleteAttach(AttachVo vo) {
		attachDao.deleteAttach(vo);
	}
	
	@Override
	public void deleteAttachRel(AttachVo vo) {
		attachDao.deleteAttachRel(vo);
	}

	@Override
	public void deleteAttachById(String attId) {
		attachDao.deleteAttachById(attId);
	}

	/**
	 * 允许添加多个附件入库，考虑到上传的文件数量不多，不用批量处理
	 */
	@Override
	public void addMultiAttach(List<AttachVo> attachVos) {
		for (int i = 0; attachVos != null && i < attachVos.size(); i++) {
			AttachVo attachVo = attachVos.get(i);
			//上传成功的文件保存入库
			saveValidAttach(attachVo);
		}
	}

	/**
	 * 保存上传有效的附件到数据库
	 */
	public void saveValidAttach(AttachVo attachVo) {
		if (attachVo != null && Constant.FILE_UPLOAD_SUCCESS.equals(attachVo.getIsOK())) {
			Employee employee = SessionUtils.getEmployee();
			String empId = employee.getID();
			attachVo.setCreateId(empId);
			attachDao.addAttach(attachVo);
		}
	}
	
	/**
	 * 将附件状态更新为DEL
	 * @author ex-weicb
	 * @createDate 2016年5月4日 下午4:05:26
	 * @param attId
	 */
	public void update2DelByAttId(String attId){
		attachDao.update2DelByAttId(attId);
	}

	/**
	 * 根据附件ID，获取附件大小,若附件不存在，则返回0
	 * 
	 * @param attId
	 * @return
	 */
	@Override
	public int getAttSize(String attId) {
		int size = 0;
		try {
			AttachVo attachVo = findById(attId);
			if (attachVo != null) {
				String filePath = attachVo.getAttPath();
				size = FileUtil.getFileSize(filePath);// 优先取物理文件size，若无数据，则取blob
				if (size == 0) {
					byte[] data = attachVo.getAttBlob();
					if (data != null && data.length > 0) {
						size = data.length;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}
		return size;
	}

	@Override
	public void updateAttach(AttachVo vo) {
		attachDao.updateAttach(vo);
	}
	
	@Override
	public void downloadAttach(String attId, HttpServletRequest request, HttpServletResponse response, String isUpload) throws IOException, ValidateFailedException {
		String resultMsg = "";
		boolean resultFlag = false;
		try {
			AttachVo attachVo = new AttachVo();
			if (StringUtils.isBlank(attId)) {
				throw new ValidateFailedException("attId为空");
			}
			attachVo = findById(attId);
			if (attachVo == null) {
				throw new ValidateFailedException("附件不存在");
			}
			String fileName = attachVo.getAttName();
			if (StringUtils.isBlank(fileName)) {
				throw new ValidateFailedException("文件名为空");
			}
			String type = "";
			String openType = "inline";
			int filename_size = fileName.lastIndexOf(".");
			String fileNameExt = "";
			String path = attachVo.getAttPath();
			if (filename_size >= 0) {
				fileNameExt = fileName.substring(fileName.lastIndexOf("."), fileName.length());
				if (fileNameExt.toLowerCase().equals(".pdf")) {
					type = "application/pdf";
				} else if (fileNameExt.toLowerCase().equals(".doc")) {
					type = "application/x-word";
				} else if (fileNameExt.toLowerCase().equals(".docx")) {
					type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
				} else if (fileNameExt.toLowerCase().equals(".xls")) {
					type = "application/vnd.ms-excel";
				} else if (fileNameExt.toLowerCase().equals(".xlsx")) {
					type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
				} else if (fileNameExt.toLowerCase().equals(".bmp")) {
					type = "image/bmp";
				} else if (fileNameExt.toLowerCase().equals(".gif")) {
					type = "image/gif";
				} else if (fileNameExt.toLowerCase().equals(".jpe") || fileNameExt.toLowerCase().equals(".jpeg") || fileNameExt.toLowerCase().equals(".jpg")) {
					type = "image/jpeg";
				} else {
					type = "application/x-msdownload";
					openType = "attachment";
				}
			} else {
				type = "application/x-msdownload";
				openType = "attachment";
			}
			if(StringUtils.isNotBlank(isUpload) && "Y".equals(isUpload)){
				openType = "attachment";
			}
			response.reset();
			response.setHeader("Content-Type", type);
			String userAgent = request.getHeader("User-Agent");
			//Edge;
			if ("Edge".contains(userAgent)) {
				fileName = URLEncoder.encode(fileName, "UTF-8");
				fileName = fileName.replace("+", "%20");
			//Chrome
			}else if ("Chrome".contains(userAgent)) {
				fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
			//IE
			}else if ("Trident".contains(userAgent)) {
				fileName = URLEncoder.encode(fileName, "UTF-8");
				fileName = fileName.replace("+", "%20");
			//Others
			}else {
				fileName = new String(fileName.getBytes("gbk"),"ISO8859-1");
			}
			response.setHeader("Content-Disposition", openType + ";filename=" + fileName);
			OutputStream outputStream = null;
			File file = null;
			if (StringUtils.isNotBlank(path)) {
				try{
					file = new File(path);
				}catch(Exception e){
					e.printStackTrace();
					log.error("附件不存在", e);
				}
			}
			if (file != null && file.exists()) {
				// 读取物理文件
				FileInputStream fis = null;
				try {
					fis = new FileInputStream(file);
					byte[] buffer = new byte[1024];
					int byteread = 0;
					outputStream = response.getOutputStream();
					while ((byteread = fis.read(buffer)) != -1) {
						outputStream.write(buffer, 0, byteread);
					}
				} catch (Exception ex) {
					ex.printStackTrace();
					log.error("附件不存在", ex);
					throw new ValidateFailedException("附件不存在");
				} finally {
					try {
						if (outputStream != null) {
							outputStream.close();
						}
						if (fis != null)
							fis.close();
					} catch (Exception ex2) {
						log.error("关闭大对象异常", ex2);
						throw new ValidateFailedException("关闭大对象异常");
					}
					resultFlag = true;
				}
			} else {
				// 读取 attblob字段
				try {
					byte[] data = attachVo.getAttBlob();
					if (data != null && data.length > 0) {
						outputStream = response.getOutputStream();
						outputStream.write(attachVo.getAttBlob());
						outputStream.flush();
					} else{
						throw new ValidateFailedException("读取 attblob字段，数据为空");
					}
				} catch (Exception ex2) {
					log.error("附件输出异常，客户端中断", ex2);
					throw new ValidateFailedException("附件输出异常，客户端中断");
				} finally {
					try {
						if (outputStream != null) {
							outputStream.close();
							outputStream = null;
						}
					} catch (Exception ex2) {
						outputStream = null;
						log.error("关闭大对象异常", ex2);
						throw new ValidateFailedException("关闭大对象异常");
					}
					resultFlag = true;
				}
			}
		} catch (Exception e) {
			resultFlag = false;
			resultMsg = e.getMessage();
		}
		if (!resultFlag) {
			response.setContentType("text/html;charset=UTF-8");
			request.setCharacterEncoding("UTF-8");
			response.setCharacterEncoding("UTF-8");
			throw new ValidateFailedException("下载附件错误：" + resultMsg);
		}
	}
	
	@Override
	public void downloadAttachZip(Map<String,String> attIds, Map<String, Map<String, File>> zipFileMap, String fileName, HttpServletRequest request, HttpServletResponse response) {
		if(null != attIds && attIds.size() != 0){
			downloadAttachZipNew(attIds, zipFileMap, fileName, request, response);
		}
	}
	
	@Override
	public void downloadAttachZip(Map<String,String> attIds,String fileName, HttpServletRequest request, HttpServletResponse response) {
		if(null != attIds && attIds.size() != 0){
			downloadAttachZipNew(attIds, null,fileName, request, response);
		}
	}
	
	@Override
	public void downloadAttachZip(String attIds,String fileName, HttpServletRequest request, HttpServletResponse response) {
		Map<String,String> map = new HashMap<String, String>();
		map.put("", attIds);
		downloadAttachZipNew(map, null, fileName, request, response);
	}
	
	public void downloadAttachZipNew(Map<String,String> attIds, Map<String, Map<String, File>> zipFileMap, String fileName, HttpServletRequest request, HttpServletResponse response){
		try {
			fileName = fileName + ".zip";
			
			// Map<文件夹名, Map<文件名, 文件>>
			Map<String,Map<String, File>> fileMap = new HashMap<String, Map<String, File>>();
			Set<String> fileNameSet = new HashSet<String>();
			AttachVo attachVo = null;
			String attId = null;
			String path = null;
			File file = null;
			String tmpName = null;
			
			for(String key : attIds.keySet()){
				if(StringUtils.isNotEmpty(attIds.get(key))){
					String strAttd[] = attIds.get(key).split(",");
					Map<String, File> files = new HashMap<String, File>();
					for (int i = 0; i < strAttd.length; i++) {
						attId = strAttd[i];
						if (attId == null || "".equals(attId)) {
							continue;
						}
						attachVo = attachDao.findById(attId);
						if(attachVo != null){
							// 文件路径
							path = attachVo.getAttPath();
							// 文件名称
							tmpName = attachVo.getAttName();
							if (StringUtils.isBlank(tmpName)) {
								continue;
							}
							try {
								if (path != null) {
									file = new File(path);
								}
							} catch (Exception e) {
								e.printStackTrace();
								log.debug("创建文件失败：" + e);
							}
							if (file == null || !file.exists()) {
								file = new File(tmpName);
								// 若文件不存在，则读取attblob
								byte[] data = attachVo.getAttBlob();
								if (data != null && data.length > 0) {
									FileOutputStream fos = null;
									try {
										fos = new FileOutputStream(file);
										fos.write(data);
									} catch (FileNotFoundException e) {
										e.printStackTrace();
									} finally {
										if (fos != null)
											fos.close();
									}
								}
							}
							if (!fileNameSet.contains(tmpName)) {
								fileNameSet.add(tmpName);
							} else {
								File renameFile = files.remove(tmpName);
								long dateTimeStr1 = System.nanoTime();
								String tmpName2 = tmpName.substring(0, tmpName.lastIndexOf(".")) + "（" + dateTimeStr1 + "）." + tmpName.substring(tmpName.lastIndexOf(".") + 1, tmpName.length());
								files.put(tmpName2, renameFile);
								long dateTimeStr = System.nanoTime();
								tmpName = tmpName.substring(0, tmpName.lastIndexOf(".")) + "（" + dateTimeStr + "）." + tmpName.substring(tmpName.lastIndexOf(".") + 1, tmpName.length());
							}
							files.put(tmpName, file);
						}
					}
					fileMap.put(String.valueOf(key), files);
				}
			}
			
			// 与外部文件夹相同
			if (zipFileMap != null && !zipFileMap.isEmpty()) {
				for (String zipFileKey : zipFileMap.keySet()) {
					Map<String, File> map = zipFileMap.get(zipFileKey);
					
					if (fileMap.containsKey(zipFileKey)) {
						Map<String, File> dirMap = fileMap.get(zipFileKey);
						// 文件名，文件
						dirMap.putAll(map);
					} else {
						fileMap.put(zipFileKey, map);
					}
				}
			}
			
			
			log.debug("AttachController===>downloadAttachZip  开始压缩下载");
			HttpDownFileZipUtil.downLoadFiles(fileName, fileMap, request, response);
			log.debug("AttachController===>downloadAttachZip  结束压缩下载");
		} catch (Exception e) {
			log.error("AttachController===>downloadAttachZip" + e.getMessage());
			e.printStackTrace();
		}
	}
	
	@Override
	public FileVo getFileByAttId(String attId) throws FileNotFoundException {
		FileVo fileVo = new FileVo();
		if (StringUtils.isBlank(attId)) {
			throw new FileNotFoundException();
		}
		File file = null;
		AttachVo attachVo = findById(attId);
		if (attachVo != null) {
			fileVo.setFileRealName(attachVo.getAttName());
			fileVo.setIsTransformFileName(true);
			String path = attachVo.getAttPath();
			if (StringUtils.isNotBlank(path)) {
				file = new File(path);
			} else {
				// 读取 attblob字段
				FileInputStream fis = null;
				try {
					byte[] data = attachVo.getAttBlob();
					if (data != null && data.length > 0) {
						file = new File(attachVo.getAttName());
						fis = new FileInputStream(file);
						fis.read(data);
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					if (fis != null) {
						try {
							fis.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}
		} else {
			throw new FileNotFoundException();
		}
		fileVo.setFile(file);
		return fileVo;
	}

	/**
	 * 根据附件关系类型、资源ID，获取附件
	 * @param attIds
	 * @return
	 */
	@Override
	public List<AttachVo> queryAttachByRelIdAndType(String relId, String relType) {
		return attachDao.queryAttachByRelIdAndType(relId, relType);
	}

	@Override
	public void updateAttachFilePathByAttId(List<Map<String, String>> tmpList) {
		if (tmpList.size() > 0) {
			for (Map<String, String> one : tmpList) {
				if ("TRUE".equalsIgnoreCase(one.get("ISTEMPFILE"))) {
					AttachVo attachVo = new AttachVo();
					attachVo.setAttId(one.get("ATTID"));
					attachVo.setAttPath(one.get("FILEPATH"));
					attachDao.updateAttachFilePathByAttId(attachVo);
				}
			}
		}
	}
	
	/**
	 * 获取附件
	 * @param attIds
	 * @return
	 */
	public List<AttachVo> findByIds(String[] attIds){
		return attachDao.findByIds(attIds);
	}
	
	/**
	 * 新增附件关联关系扩展信息
	 * @param attRelId
	 * @param attrName
	 * @param attrValue
	 */
//	@Override
//	public void insertAttExt(String attId, String attrName, String attrValue){
//		if(StringUtils.isNotBlank(attId) && 
//		   StringUtils.isNotBlank(attrName) && 
//		   StringUtils.isNotBlank(attrValue)){
//		   String createId = SessionUtils.getEmployee().getID();
//		   AttachRelExtVo attachExtVo = new AttachRelExtVo();
//		   attachExtVo.setAttId(attId);
//		   attachExtVo.setAttrName(attrName);
//		   attachExtVo.setAttrValue(attrValue);
//		   attachDao.insertAttExt(attId, attrName, attrValue, createId);
//		}
//	}
	
	@Override
	public int addAttachRel2(String empId, String bussessId, String relType, String attIds) {
		return attachDao.addAttachRel2(empId, bussessId, relType, attIds);
	}

	@Override
	public int deleteAttachRel2(String bussessId, String relType) {
		return attachDao.deleteAttachRel2(bussessId, relType);
	}
	
	@Override
	public int deleteAttachRelByAttId(String attId) {
		return attachDao.deleteAttachRelByAttId(attId);
	}
	

	@Override
	public void alterAttachRel(String sourceId, String sourceSign, String attIds) {
		if(StringUtils.isBlank(sourceId) || StringUtils.isBlank(sourceSign)) {
			throw new IllegalArgumentException("参数sourceId及sourceSign不能为空");
		}
		
		// 删除之前的关联关系
		attachDao.deleteAttachRel2(sourceId, sourceSign);
		
		if(StringUtils.isNotBlank(attIds)) {
			String empId = SessionUtils.getEmployee().getID();
			attachDao.addAttachRel2(empId, sourceId, sourceSign, attIds);
		}
	}

//	@Override
//	public AttachInfoExtVo queryAttExtById(String extId) {
//		return attachDao.queryAttExtById(extId);
//	}

//	@Override
//	public void updateAttExt(AttachInfoExtVo attachExtVo) {
//		attachDao.updateAttExt(attachExtVo);
//	}

//	@Override
//	public void insertAttExt(String attId, String attrName, String attrValue, String userId) {
//		attachDao.insertAttExt(attId, attrName, attrValue, userId);
//	}

	@Override
	public List<AttachRelExtVo> listAttachExtByAttId(String attId) {
		return attachDao.listAttachExtByAttId(attId);
	}

	@Override
	public Page<AttachVo> attAndRelAndExtListPage(SearchParam sp) {
		String empId = SessionUtils.getEmployee().getID();
		if (StringUtils.equals(SessionUtils.getEmployee().getEmpType(), "OUT")) {
			sp.getSp().put("empId", empId);
		}
		List<AttachVo> items = attachDao.attAndRelAndExtListPage(sp);
		return Page.create(items, sp.getStart(), sp.getLimit(), sp.getTotal());
	}
	
	@Override
	public List<AttachVo> attAndRelAndExtList(SearchParam sp) {
		List<AttachVo> items = attachDao.attAndRelAndExtListPage(sp);
		return items;
	}

	@Override
	public List<AttachVo> batchDownAttach(SearchParam sp) {
		return attachDao.batchDownAttach(sp);
	}

}
